﻿extern "C" {
#include <curl/curl.h>
}
#include <QJsonObject>
#include <QtConcurrent/QtConcurrent>
#include <QModbusDevice>
#include "Frameworks/AbstruactEventMediator.h"
#include "DrillingrigQmlEvent.h"

struct NetworkData
{
	const char* data;
	size_t size;
	static size_t read_callback(char* buffer, size_t size, size_t nitems, void* instream) {
#if 0	//使用UploadData结构
		size_t bytes_to_copy = size * nitems;
		UploadData* data = static_cast<UploadData*>(instream);
		if (bytes_to_copy > data->size) {
			bytes_to_copy = data->size;
		}

		std::memcpy(buffer, data->data, bytes_to_copy);
		data->data += bytes_to_copy;
		data->size -= bytes_to_copy;

		return bytes_to_copy;
#else	//直接使用QByteArray
		QByteArray* data = reinterpret_cast<QByteArray*>(instream);
		size_t len = data->size();
		if (len > size * nitems) len = size * nitems;
		memcpy(buffer, data->data(), len);
		data->remove(0, len);
		return len;
#endif
	}
	static int progress(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
		DrillingrigQmlEvent* event = static_cast<DrillingrigQmlEvent*> (clientp);
		if (event && ultotal > 0 && ulnow > 0)
			emit event->progressValueChanged((double)ulnow / (double)ultotal);
		return 0;
	}
	static int write_callback(void* data, size_t size, size_t nmemb, void* userData) {
		QByteArray* content = static_cast<QByteArray*>(userData);
		content->append(static_cast<char*>(data), size * nmemb);
		return size * nmemb;
	}
};

DrillingrigQmlEvent::DrillingrigQmlEvent(QObject* parent /*= nullptr*/)
	: DrillingrigEvent(parent)
	, EquipmentAction()
{

}

DrillingrigQmlEvent::~DrillingrigQmlEvent() {

}

void DrillingrigQmlEvent::update(QJsonObject const& msg) {
	auto const&& command = msg[ME_MSG_KEY].toString();
	if (command == ME_REPORTLOG.toString()) {
		int level = msg["level"].toInt();
		emit logReport(msg["msg"].toString(), level);
	}
	else if (command == ME_CONNECTSTATE) {
		int state = msg["state"].toInt();
		setIsConnected(QModbusDevice::ConnectedState == state);
	}
}

void DrillingrigQmlEvent::send(QJsonObject const& msg) {
	if (m_mediator) {
		m_mediator->push(msg, DrillingrigEvent::Identity);
	}
}

void DrillingrigQmlEvent::send(QJsonObject const& msg, QStringView to) {
	if (m_mediator) {
		m_mediator->push(msg, DrillingrigEvent::Identity, to);
	}
}

void DrillingrigQmlEvent::setMediator(AbstruactEventMediator* mediator) {
	if (m_mediator != mediator) {
		m_mediator = mediator;
	}
}

QStringView DrillingrigQmlEvent::identity() const {
	return DrillingrigEvent::Identity;
}

QJsonObject DrillingrigQmlEvent::requestParams(QString const& host, quint16 port) const {
	auto f = QtConcurrent::run([h = std::move(host), p = std::move(port), this]()->QJsonObject {
		curl_global_init(CURL_GLOBAL_ALL);
		CURL* curl = curl_easy_init();
		QByteArray content;
		if (curl) {
			curl_easy_setopt(curl, CURLOPT_URL, ("ftp://" + h + "/" + "DrillPara.json").toLocal8Bit().data());
			curl_easy_setopt(curl, CURLOPT_USERNAME, "admin");
			curl_easy_setopt(curl, CURLOPT_PASSWORD, "ylkj");
			curl_easy_setopt(curl, CURLOPT_PORT, p);
			curl_easy_setopt(curl, CURLOPT_WRITEDATA, &content);
			curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &NetworkData::write_callback);
			curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, &NetworkData::progress);
			curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this);
			curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
			CURLcode res = curl_easy_perform(curl);
			if (res != CURLE_OK) {
				emit logReport(QString("FTP upload event %0.\n").arg(curl_easy_strerror(res)), 2);
				return QJsonObject();
			}
			curl_easy_cleanup(curl);
			curl_global_cleanup();
		}
		QJsonDocument doc = QJsonDocument::fromJson(content);
		return doc.object();
	});
	QEventLoop loop;
	QFutureWatcher<QJsonObject> watcher;
	connect(&watcher, &QFutureWatcher<QJsonObject>::finished, &loop, &QEventLoop::quit);
	watcher.setFuture(f);
	loop.exec();
	emit logReport("钻机参数请求成功", 0);
	return f.result();
}

bool DrillingrigQmlEvent::emitParams(QJsonObject const& params, QString const& host, quint16 port) {
	auto f = QtConcurrent::run(
		[obj = std::move(params), host = std::move(host),port = std::move(port),this]()->void {
			QJsonDocument doc(std::move(obj));
			CURL* curl = nullptr;
			curl_global_init(CURL_GLOBAL_ALL);
			curl = curl_easy_init();
			if (curl) {
				auto buffer = doc.toJson();
				curl_easy_setopt(curl, CURLOPT_URL, ("ftp://" + host + "/" + "DrillPara.json").toLocal8Bit().data());
				curl_easy_setopt(curl, CURLOPT_PORT, port);
				curl_easy_setopt(curl, CURLOPT_USERNAME, "admin");
				curl_easy_setopt(curl, CURLOPT_PASSWORD, "ylkj");
				curl_easy_setopt(curl, CURLOPT_READFUNCTION, &NetworkData::read_callback);
				curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, &NetworkData::progress);
				curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this);
				curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
				curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, 0L);
				curl_easy_setopt(curl, CURLOPT_READDATA, &buffer);
				//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);	//打印日志
				curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, buffer.size());
				curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
				CURLcode r = curl_easy_perform(curl);
				if (r != CURLE_OK) {
					emit logReport(QString("FTP upload event %0.\n").arg(curl_easy_strerror(r)), 2);
				}
				curl_easy_cleanup(curl);
				curl_global_cleanup();
			}
	});
	QFutureWatcher<void>* wathcer = new QFutureWatcher<void>;
	connect(wathcer, &QFutureWatcher<void>::finished, [wathcer, this] {
		emit logReport(QStringLiteral("钻机参数下发成功"), 0);
		wathcer->deleteLater();
	});
	wathcer->setFuture(f);
	return true;
}

void DrillingrigQmlEvent::debug(QUrl const& msg) {
	qDebug() << msg.toString();
	QString path = msg.toString();
	path.replace("qrc", "");
	qDebug() << QFileInfo::exists(path);
}
